package com.yj.lottery_system.service.impl;
import java.util.*;

import com.yj.lottery_system.common.errorcode.ServiceErrorCodeConstants;
import com.yj.lottery_system.common.exception.ServiceException;
import com.yj.lottery_system.common.utils.JacksonUtil;
import com.yj.lottery_system.common.utils.RedisUtil;
import com.yj.lottery_system.controller.param.CreateActivityParam;
import com.yj.lottery_system.controller.param.CreatePrizeByActivityParam;
import com.yj.lottery_system.controller.param.CreateUserByActivityParam;
import com.yj.lottery_system.controller.param.PageParam;
import com.yj.lottery_system.dao.dataObject.ActivityDO;
import com.yj.lottery_system.dao.dataObject.ActivityPrizeDO;
import com.yj.lottery_system.dao.dataObject.ActivityUserDO;
import com.yj.lottery_system.dao.dataObject.PrizeDO;
import com.yj.lottery_system.dao.mapper.*;
import com.yj.lottery_system.service.IActivityService;
import com.yj.lottery_system.service.dto.ActivityDTO;
import com.yj.lottery_system.service.dto.ActivityDetailDTO;
import com.yj.lottery_system.service.dto.CreateActivityDTO;
import com.yj.lottery_system.service.dto.PageListDTO;
import com.yj.lottery_system.service.enums.ActivityPrizeStatusEnum;
import com.yj.lottery_system.service.enums.ActivityPrizeTiresEnum;
import com.yj.lottery_system.service.enums.ActivityStatusEnum;
import com.yj.lottery_system.service.enums.ActivityUserStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
public class ActivityServiceImpl implements IActivityService {
    private static final Logger log = LoggerFactory.getLogger(ActivityServiceImpl.class);
    //前缀
    private final String ACTIVITY_PREFIX = "ACTIVITY_";
    //过期时间 3 天
    private final Long ACTIVITY_TIMEOUT = (long)(60 * 60 * 24 * 3);
   @Autowired
   private UserMapper userMapper;
   @Autowired
   private PrizeMapper prizeMapper;
   @Autowired
   private ActivityMapper activityMapper;
   @Autowired
   private ActivityPrizeMapper activityPrizeMapper;
   @Autowired
   private ActivityUserMapper activityUserMapper;
   @Autowired
   private RedisUtil redisUtil;
    @Override
    public CreateActivityDTO createActivity(CreateActivityParam param) {
        //校验活动信息
        checkActivityInfo(param);
        //保存 活动信息
        ActivityDO activityDO = new ActivityDO();
        activityDO.setDescription(param.getDescription());
        activityDO.setActivityName(param.getActivityName());
        activityDO.setStatus(ActivityStatusEnum.RUNNING.name());

        activityMapper.insert(activityDO);

        //保存活动关联奖品信息
        List<CreatePrizeByActivityParam> prizeParamList = param.getActivityPrizeList();
        List<ActivityPrizeDO> activityPrizeDOList = prizeParamList.stream()
                .map( prizeParam -> {
                    ActivityPrizeDO activityPrizeDO = new ActivityPrizeDO();
                    activityPrizeDO.setActivityId(activityDO.getId());
                    activityPrizeDO.setPrizeAmount(prizeParam.getPrizeAmount());
                    activityPrizeDO.setPrizeId(prizeParam.getPrizeId());
                    activityPrizeDO.setPrizeTiers(prizeParam.getPrizeTiers());
                    activityPrizeDO.setStatus(ActivityPrizeStatusEnum.INIT.name());

                    return activityPrizeDO;
                }).collect(Collectors.toList());
        activityPrizeMapper.batchInsert(activityPrizeDOList);

        //保存活动关联人员信息
        List<CreateUserByActivityParam> userParamList = param.getActivityUserList();
        List<ActivityUserDO> activityUserDOList = userParamList.stream()
                .map(userParam -> {
                    ActivityUserDO activityUserDO = new ActivityUserDO();
                    activityUserDO.setActivityId(activityDO.getId());
                    activityUserDO.setUserId(userParam.getUserId());
                    activityUserDO.setUserName(userParam.getUserName());
                    activityUserDO.setStatus(ActivityUserStatusEnum.INIT.name());
                    return activityUserDO;
                }).collect(Collectors.toList());
        activityUserMapper.batchInsert(activityUserDOList);

        //整合完整活动信息: 活动信息 奖品信息 人员信息
        //先拿到奖品id 获取奖品基本属性
        List<Long> prizeIds = param.getActivityPrizeList().stream()
                .map(CreatePrizeByActivityParam::getPrizeId)
                .distinct()
                .collect(Collectors.toList());
        List<PrizeDO> prizeDOList = prizeMapper.batchSelectByIds(prizeIds);

        // key = activityId value = ActivityDetailDTO
        ActivityDetailDTO activityDetailDTO =  convertActivityDetailDTO(activityDO,activityUserDOList, activityPrizeDOList, prizeDOList);

        // 存入Redis
        cacheActivity(activityDetailDTO);

        //构造返回
        CreateActivityDTO createActivityDTO = new CreateActivityDTO();
        createActivityDTO.setActivityId(activityDetailDTO.getActivityId());


        return createActivityDTO;
    }



    /**
     * 缓存完整信息
     */
    private void cacheActivity(ActivityDetailDTO activityDetailDTO) {
        // key = ACTIVITY_activityId value = ActivityDetailDTO(转为JSON)
        if(null == activityDetailDTO || null == activityDetailDTO.getActivityId()) {
            log.warn("要缓存的活动信息不存在");
            return;
        }
        try {
            redisUtil.set(ACTIVITY_PREFIX+ activityDetailDTO.getActivityId(), JacksonUtil.writeValueAsString(activityDetailDTO), ACTIVITY_TIMEOUT);
        }catch (Exception e) {
            log.error("缓存活动异常 activityDetailDTO：{}", JacksonUtil.writeValueAsString(activityDetailDTO),e);
        }

    }
    /**
     * 根据活动id获取缓存中的完整信息
     */
    private ActivityDetailDTO getActivityFromCache(Long activityId) {
        if(null == activityId) {
            log.warn("从缓存获取活动详细数据的活动id为空 activityId: {}",activityId);
            return null;
        }
        try {
            String s = redisUtil.get(ACTIVITY_PREFIX + activityId);
            if(!StringUtils.hasText(s)) {
                log.info("从缓存获取活动详细数据为空  key: {}",ACTIVITY_PREFIX + activityId);
                return null;
            }
            return  JacksonUtil.readValue(s,ActivityDetailDTO.class);
        }catch (Exception e) {
            log.error("从缓存获取活动详细数据异常  key: {}",ACTIVITY_PREFIX + activityId,e);
            return null;
        }
    }
    /**
     *整合完整活动信息: 活动信息 奖品信息 人员信息
     */
    private ActivityDetailDTO convertActivityDetailDTO(ActivityDO activityDO,
                                                       List<ActivityUserDO> activityUserDOList,
                                                       List<ActivityPrizeDO> activityPrizeDOList,
                                                       List<PrizeDO> prizeDOList) {
        ActivityDetailDTO activityDetailDTO = new ActivityDetailDTO();
        activityDetailDTO.setActivityId(activityDO.getId());
        activityDetailDTO.setActivityName(activityDO.getActivityName());
        activityDetailDTO.setDesc(activityDO.getDescription());
        activityDetailDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));

        List<ActivityDetailDTO.PrizeDTO> prizeDTOList = activityPrizeDOList
                .stream()
                .map(activityPrizeDO -> {
                    ActivityDetailDTO.PrizeDTO prizeDTO = new ActivityDetailDTO.PrizeDTO();
                    prizeDTO.setPrizeId(activityPrizeDO.getPrizeId());
                   Optional<PrizeDO> optionalPrizeDO = prizeDOList.stream()
                            .filter(prizeDO -> prizeDO.getId().equals(activityPrizeDO.getPrizeId()))
                            .findFirst();
                   //如果PrizeDO 空，不会走下面逻辑
                   optionalPrizeDO.ifPresent(prizeDO -> {
                       prizeDTO.setDescription(prizeDO.getDescription());
                       prizeDTO.setImageUrl(prizeDO.getImageUrl());
                       prizeDTO.setName(prizeDO.getName());
                       prizeDTO.setPrice(prizeDO.getPrice());
                   });

                    prizeDTO.setTires(ActivityPrizeTiresEnum.forName(activityPrizeDO.getPrizeTiers()));
                    prizeDTO.setPrizeAmount(activityPrizeDO.getPrizeAmount());
                    prizeDTO.setStatus(ActivityPrizeStatusEnum.forName(activityPrizeDO.getStatus()));


                    return prizeDTO;
                }).collect(Collectors.toList());
        activityDetailDTO.setPrizeDTOList(prizeDTOList);

        List<ActivityDetailDTO.UserDTO> userDTOList = activityUserDOList.stream()
                        .map(activityUserDO -> {
                            ActivityDetailDTO.UserDTO userDTO = new ActivityDetailDTO.UserDTO();
                            userDTO.setUserId(activityUserDO.getUserId());
                            userDTO.setUserName(activityUserDO.getUserName());
                            userDTO.setStatus(ActivityUserStatusEnum.forName(activityUserDO.getStatus()));

                            return userDTO;
                        }).collect(Collectors.toList());
        activityDetailDTO.setUserDTOList(userDTOList);
        return activityDetailDTO;
    }

    /**
     * 创建活动 校验活动信息
     * @param param
     */
    private void checkActivityInfo(CreateActivityParam param) {
        if(null == param) {
            throw new ServiceException(ServiceErrorCodeConstants.CREATE_ACTIVITY_INFO_IS_EMPTY);
        }

        //人员id在user表存在
        //拿参数里面的人员id
        List<Long> userIds = param.getActivityUserList().stream()
                .map(CreateUserByActivityParam::getUserId)
                .distinct()
                .collect(Collectors.toList());
        //数据库存在的人员id
        List<Long> exitsUserIds = userMapper.selectExitsByIds(userIds);
        if(CollectionUtils.isEmpty(exitsUserIds)) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR);
        }
        userIds.forEach(id -> {
            if(!exitsUserIds.contains(id)) {
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_USER_ERROR);
            }
        });

        //奖品id在prize表存在
        //拿参数里面的奖品id
        List<Long> prizeIds = param.getActivityPrizeList().stream()
                .map(CreatePrizeByActivityParam::getPrizeId)
                .distinct()
                .collect(Collectors.toList());
        //数据库存在的奖品id
        List<Long> exitsPrizeIds = prizeMapper.selectExitsByIds(prizeIds);
        if(CollectionUtils.isEmpty(exitsPrizeIds)) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR);
        }
        prizeIds.forEach(id -> {
            if(!exitsPrizeIds.contains(id)) {
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR);
            }
        });

        //人员数量大于等于奖品数量
        int userCount = param.getActivityUserList().size();
        long prizeCount = param.getActivityPrizeList().stream()
                .mapToLong(CreatePrizeByActivityParam :: getPrizeAmount)
                .sum();
        if( userCount < prizeCount) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_USER_PRIZE_COUNT_ERROR);
        }
        //校验活动奖品等级
        param.getActivityPrizeList().forEach(prize -> {
            if(null == ActivityPrizeTiresEnum.forName(prize.getPrizeTiers())) {
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_TIERS_ERROR);
            }
        });
    }
    /**
     * 分页获取活动基本信息列表
     * @param param
     * @return
     */
    @Override
    public PageListDTO<ActivityDTO> findActivityList(PageParam param) {
        //获取总量
        int total = activityMapper.count();
        //获取当前页活动列表
        int offset = (param.getCurrentPage() - 1) * param.getPageSize();
        List<ActivityDO> activityDOList = activityMapper.selectActivityList(offset,param.getPageSize());
        List<ActivityDTO> activityDTOList = activityDOList.stream()
                .map(activityDO -> {
                    ActivityDTO activityDTO = new ActivityDTO();
                    activityDTO.setActivityId(activityDO.getId());
                    activityDTO.setActivityName(activityDO.getActivityName());
                    activityDTO.setDescription(activityDO.getDescription());
                    activityDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));

                    return activityDTO;
                }).collect(Collectors.toList());

        return new PageListDTO<>(total,activityDTOList);
    }

    /**
     * 获取活动详情信息
     * @param activityId
     * @return
     */
    @Override
    public ActivityDetailDTO getActivityDetailFind(Long activityId) {
        //查Redis
        if(null == activityId) {
            log.warn("查询活动详细信息失败 activityId不存在");
            return null;
        }
        ActivityDetailDTO activityFromCache = getActivityFromCache(activityId);
        if(activityFromCache != null) {
            log.warn("查询活动详细信息成功 activityFromCache：{}", JacksonUtil.writeValueAsString(activityFromCache));
            return activityFromCache;
        }
        //如果Redis没有，
        // 查表 活动表
        ActivityDO activityDO = activityMapper.selectById(activityId);
        // 活动奖品表
        List<ActivityPrizeDO> activityPrizeDOList = activityPrizeMapper.selectByActivityId(activityId);
        // 活动人员表
        List<ActivityUserDO> activityUserDOList = activityUserMapper.selectByActivityId(activityId);
        // 奖品表
        //先拿奖品id
        List<Long> prizeIdList = activityPrizeDOList.stream()
                .map(ActivityPrizeDO::getPrizeId)
                .collect(Collectors.toList());
        List<PrizeDO> prizeDOList = prizeMapper.batchSelectByIds(prizeIdList);

        //整合详细信息，存放Redis
        ActivityDetailDTO activityDetailDTO = convertActivityDetailDTO(activityDO, activityUserDOList, activityPrizeDOList, prizeDOList);
        //存放Redis
        cacheActivity(activityDetailDTO);
        return activityDetailDTO;
    }

    /**
     * 缓存活动详细信息（读取表数据
     */
    @Override
    public void cacheActivity(Long activityId) {
        if(null == activityId) {
            log.warn("缓存的活动ID为空");
            throw new ServiceException(ServiceErrorCodeConstants.CACHE_ACTIVITY_ID_IS_EMPTY);
        }
    //查询表数据 活动表 活动奖品表 活动人员表
        // 查表 活动表
        ActivityDO activityDO = activityMapper.selectById(activityId);
        if(null == activityDO) {
            log.error("缓存的活动ID有误");
            throw new ServiceException(ServiceErrorCodeConstants.CACHE_ACTIVITY_ID_ERROR);
        }
        // 活动奖品表
        List<ActivityPrizeDO> activityPrizeDOList = activityPrizeMapper.selectByActivityId(activityId);
        // 活动人员表
        List<ActivityUserDO> activityUserDOList = activityUserMapper.selectByActivityId(activityId);
        // 奖品表
        //先拿奖品id
        List<Long> prizeIdList = activityPrizeDOList.stream()
                .map(ActivityPrizeDO::getPrizeId)
                .collect(Collectors.toList());
        List<PrizeDO> prizeDOList = prizeMapper.batchSelectByIds(prizeIdList);

        //整合详细信息，存放Redis
        ActivityDetailDTO activityDetailDTO = convertActivityDetailDTO(activityDO, activityUserDOList, activityPrizeDOList, prizeDOList);
        //存放Redis
        cacheActivity(activityDetailDTO);
    }
}
